
const isObject = target => target !== null && typeof target === 'object'
const convert = target => isObject(target) ? reactive(target) : target
const hasOwnProperty = Object.prototype.hasOwnProperty
const hasOwn = (target,key)=>hasOwnProperty.call(target,key)

export  function reactive(target){
    if(!isObject(target)) return
    const handler = {
        get(target,key,receiver){
            const result = Reflect.get(target,key,receiver)
            // console.log('get')
            track(target,key) // 收集依赖
            return convert(result)
        },
        set(target,key,value,receiver){
            const oldVal = Reflect.get(target,key,receiver)
            let flag = true
            if(oldVal !== value){
                flag = Reflect.set(target,key,value,receiver)
                trigger(target,key) // 触发更新
            }
            // console.log('set')
            return flag
        },
        deleteProperty(target,key){
            const hasKey = hasOwn(target,key)
            const result = Reflect.deleteProperty(target,key)
            if(hasKey && result){
               trigger(target,key) // 触发更新
            }
            // console.log('delete')
            return result
        }
    }
    return new Proxy(target,handler)
}

let activeEffect = null 
export function effect(callback){
    activeEffect = callback
    callback() // 先执行一次，会触发 get 方法
    activeEffect = null
}

// 收集依赖
let targetMap = new WeakMap()
export function track(target,key){
    if(!activeEffect) return
    let depsMap = targetMap.get(target)
    if(!depsMap) targetMap.set(target,depsMap = new Map())
    let dep = depsMap.get(key)
    if(!dep) depsMap.set(key,dep = new Set())
    dep.add(activeEffect)
}

export function trigger(target,key){
    const depsMap = targetMap.get(target)
    if(!depsMap)return
    const dep = depsMap.get(key)
    if(!dep)return
    dep.forEach(callback=>callback())
}


// ref 可以把基本类型数据转换为响应式对象，重新赋值得到的也是响应式对象
// reactive 返回的对象重新赋值丢失响应式，不能解构，可以使用 toRefs 处理才能解构
// 对象成员比较多，使用 ref 不方便
export function ref(raw){
    if(isObject(raw) && hasOwn(raw,'__v_isRef')) return
    let value = convert(raw)
    const r = {
        __v_isRef:true,
        get value(){
            track(r,'value')
            return value
        },
        set value(newVal){
            if(newVal !== value){
                raw = newVal
                value = convert(raw)
                trigger(r,'value')
            }
        }
    }
    return r
}

export function toRefs(proxy){
    const ret = proxy instanceof Array ? new Array(proxy.length) : {}
    for(const key in proxy){
        ret[key] = toProxyRef(proxy,key)
    }
    return ret
}
// proxy 是响应式的，不需要收集依赖、触发更新
function toProxyRef(proxy,key){
    const r = {
        __v_isRef:true,
        get value(){
            return proxy[key]
        },
        set value(newVal){
            proxy[key] = newVal
        }
    }
    return r
}

export function computed(getter){
    const result = ref() // value 值是 undefined
    effect(()=> (result.value = getter()))
    return result
}

